package com.kk.xhr.model.service.impl;

import com.kk.xhr.common.pojo.EmployeeStatusEnum;
import com.kk.xhr.model.assembler.EmployeeStructKit;
import com.kk.xhr.model.dao.EducationExperienceDynamicSqlSupport;
import com.kk.xhr.model.dao.EducationExperienceMapper;
import com.kk.xhr.model.dao.EmployeeDynamicSqlSupport;
import com.kk.xhr.model.dao.EmployeeMapper;
import com.kk.xhr.model.dao.JobExperienceDynamicSqlSupport;
import com.kk.xhr.model.dao.JobExperienceMapper;
import com.kk.xhr.model.dao.PrizeExperienceDynamicSqlSupport;
import com.kk.xhr.model.dao.PrizeExperienceMapper;
import com.kk.xhr.model.dao.ProjectExperienceDynamicSqlSupport;
import com.kk.xhr.model.dao.ProjectExperienceMapper;
import com.kk.xhr.model.dao.custom.CommonCustomMapper;
import com.kk.xhr.model.dto.EducationExperienceModifyRequestDTO;
import com.kk.xhr.model.dto.EmployeeDTO;
import com.kk.xhr.model.dto.EmployeeQueryRequestDTO;
import com.kk.xhr.model.dto.JobExperienceModifyRequestDTO;
import com.kk.xhr.model.dto.PageDto;
import com.kk.xhr.model.dto.PrizeExperienceModifyRequestDTO;
import com.kk.xhr.model.dto.ProjectExperienceModifyRequestDTO;
import com.kk.xhr.model.entity.EducationExperience;
import com.kk.xhr.model.entity.Employee;
import com.kk.xhr.model.entity.JobExperience;
import com.kk.xhr.model.entity.PrizeExperience;
import com.kk.xhr.model.entity.ProjectExperience;
import com.kk.xhr.model.service.IEmployeeService;
import lombok.RequiredArgsConstructor;
import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider;
import org.mybatis.dynamic.sql.render.RenderingStrategies;
import org.mybatis.dynamic.sql.where.AbstractWhereDSL;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static org.mybatis.dynamic.sql.SqlBuilder.insertMultiple;
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualToWhenPresent;
import static org.mybatis.dynamic.sql.SqlBuilder.isLikeWhenPresent;

/**
 * employee 接口实现
 *
 * @author luokexiong
 * @version 1.0 2021/2/15
 * @since 1.0.0
 */
@Repository
@RequiredArgsConstructor
public class EmployeeServiceImpl implements IEmployeeService {

    private final EmployeeMapper employeeMapper;
    private final JobExperienceMapper jobExperienceMapper;
    private final PrizeExperienceMapper prizeExperienceMapper;
    private final EducationExperienceMapper educationExperienceMapper;
    private final ProjectExperienceMapper projectExperienceMapper;
    private final CommonCustomMapper commonCustomMapper;

    /**
     * {@inheritDoc}
     */
    @Override
    public long add(EmployeeDTO dto) {
        Employee entity = EmployeeStructKit.INSTANCE.toEntity(dto);
        employeeMapper.insertSelective(entity);
        return entity.getId();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public long addPrize(PrizeExperience prize) {
        prizeExperienceMapper.insertSelective(prize);
        return prize.getId();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public long addEducation(EducationExperience education) {
        educationExperienceMapper.insertSelective(education);
        return education.getId();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public long addProject(ProjectExperience project) {
        projectExperienceMapper.insertSelective(project);
        return project.getId();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public long addJob(JobExperience job) {
        jobExperienceMapper.insertSelective(job);
        return job.getId();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public PageDto<EmployeeDTO> query(EmployeeQueryRequestDTO dto) {
        long count = employeeMapper.count(dsl -> applyQueryArgs(dsl.where(), dto));
        if (0 == count) {
            return PageDto.empty();
        }
        return new PageDto<>(count, employeeMapper.select(dsl -> applyQueryArgs(dsl.where(), dto)
            .limit(dto.getLimit()).offset(dto.getOffset()))
            .stream()
            .map(EmployeeStructKit.INSTANCE::toDto)
            .collect(Collectors.toList()));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Optional<EmployeeDTO> queryByUserId(Long userId) {
        return employeeMapper.selectOne(dsl -> dsl
            .where(EmployeeDynamicSqlSupport.userId, isEqualTo(userId)).limit(1))
            .map(EmployeeStructKit.INSTANCE::toDto);
    }

    @Override
    public List<JobExperience> queryJob(Long employeeId) {
        return jobExperienceMapper.select(dsl -> dsl
            .where(JobExperienceDynamicSqlSupport.employeeId, isEqualTo(employeeId)));
    }

    @Override
    public List<PrizeExperience> queryPrize(Long employeeId) {
        return prizeExperienceMapper.select(dsl -> dsl
            .where(PrizeExperienceDynamicSqlSupport.employeeId, isEqualTo(employeeId)));
    }

    @Override
    public List<EducationExperience> queryEducation(Long employeeId) {
        return educationExperienceMapper.select(dsl -> dsl
            .where(EducationExperienceDynamicSqlSupport.employeeId, isEqualTo(employeeId)));
    }

    @Override
    public List<ProjectExperience> queryProject(Long employeeId) {
        return projectExperienceMapper.select(dsl -> dsl
            .where(ProjectExperienceDynamicSqlSupport.employeeId, isEqualTo(employeeId)));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean modify(Long id, EmployeeStatusEnum status) {
        if (null == status) {
            return false;
        }
        Employee employee = new Employee();
        employee.setId(id);
        employee.setStatus(status.getValue());
        return 1 == employeeMapper.updateByPrimaryKey(employee);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean modify(EmployeeDTO dto) {
        return 1 == employeeMapper.updateByPrimaryKeySelective(EmployeeStructKit.INSTANCE.toEntity(dto));
    }

    @Override
    public boolean modifyJob(JobExperienceModifyRequestDTO dto) {
        return 1 == jobExperienceMapper.updateByPrimaryKeySelective(new JobExperience()
            .withId(dto.getId())
            .withCompany(dto.getCompany())
            .withContent(dto.getContent())
            .withPosition(dto.getPosition())
            .withBegin(dto.getBegin())
            .withEnd(dto.getEnd()));
    }

    @Override
    public boolean modifyPrize(PrizeExperienceModifyRequestDTO dto) {
        return 1 == prizeExperienceMapper.updateByPrimaryKeySelective(new PrizeExperience()
            .withId(dto.getId())
            .withContent(dto.getContent())
            .withTitle(dto.getTitle())
            .withFileId(dto.getFileId())
            .withAwardTime(dto.getAwardTime()));
    }

    @Override
    public boolean modifyEducation(EducationExperienceModifyRequestDTO dto) {
        EducationExperience entity = new EducationExperience()
            .withId(dto.getId())
            .withSchool(dto.getSchool())
            .withBegin(dto.getBegin())
            .withEnd(dto.getEnd());
        if (null != dto.getDegree()) {
            entity.withDegree(dto.getDegree().getValue());
        }
        return 1 == educationExperienceMapper.updateByPrimaryKeySelective(entity);
    }

    @Override
    public boolean modifyProject(ProjectExperienceModifyRequestDTO dto) {
        return 1 == projectExperienceMapper.updateByPrimaryKeySelective(new ProjectExperience()
            .withId(dto.getId())
            .withTitle(dto.getTitle())
            .withRole(dto.getRole())
            .withContent(dto.getContent())
            .withBegin(dto.getBegin())
            .withEnd(dto.getEnd()));
    }

    @Override
    public boolean removeJob(Long id) {
        return 1 == jobExperienceMapper.deleteByPrimaryKey(id);
    }

    @Override
    public boolean removePrize(Long id) {
        return 1 == prizeExperienceMapper.deleteByPrimaryKey(id);
    }

    @Override
    public boolean removeEducation(Long id) {
        return 1 == educationExperienceMapper.deleteByPrimaryKey(id);
    }

    @Override
    public boolean removeProject(Long id) {
        return 1 == prizeExperienceMapper.deleteByPrimaryKey(id);
    }

    @Override
    public int batchAddJob(Collection<JobExperience> jobs) {
        MultiRowInsertStatementProvider<JobExperience> provider = insertMultiple(jobs)
            .into(JobExperienceDynamicSqlSupport.jobExperience)
            .map(JobExperienceDynamicSqlSupport.employeeId).toProperty("employeeId")
            .map(JobExperienceDynamicSqlSupport.company).toProperty("company")
            .map(JobExperienceDynamicSqlSupport.content).toProperty("content")
            .map(JobExperienceDynamicSqlSupport.position).toProperty("position")
            .map(JobExperienceDynamicSqlSupport.begin).toProperty("begin")
            .map(JobExperienceDynamicSqlSupport.end).toProperty("end")
            .build().render(RenderingStrategies.MYBATIS3);
        return commonCustomMapper.insertMultiple(provider);
    }

    @Override
    public int batchAddPrize(Collection<PrizeExperience> prizes) {
        MultiRowInsertStatementProvider<PrizeExperience> provider = insertMultiple(prizes)
            .into(PrizeExperienceDynamicSqlSupport.prizeExperience)
            .map(PrizeExperienceDynamicSqlSupport.employeeId).toProperty("employeeId")
            .map(PrizeExperienceDynamicSqlSupport.title).toProperty("title")
            .map(PrizeExperienceDynamicSqlSupport.content).toProperty("content")
            .map(PrizeExperienceDynamicSqlSupport.fileId).toProperty("fileId")
            .map(PrizeExperienceDynamicSqlSupport.awardTime).toProperty("awardTime")
            .build().render(RenderingStrategies.MYBATIS3);
        return commonCustomMapper.insertMultiple(provider);
    }

    @Override
    public int batchAddEdu(Collection<EducationExperience> educations) {
        MultiRowInsertStatementProvider<EducationExperience> provider = insertMultiple(educations)
            .into(EducationExperienceDynamicSqlSupport.educationExperience)
            .map(EducationExperienceDynamicSqlSupport.employeeId).toProperty("employeeId")
            .map(EducationExperienceDynamicSqlSupport.school).toProperty("school")
            .map(EducationExperienceDynamicSqlSupport.degree).toProperty("degree")
            .map(EducationExperienceDynamicSqlSupport.begin).toProperty("begin")
            .map(EducationExperienceDynamicSqlSupport.end).toProperty("end")
            .build().render(RenderingStrategies.MYBATIS3);
        return commonCustomMapper.insertMultiple(provider);
    }

    @Override
    public int batchAddProject(Collection<ProjectExperience> projects) {
        MultiRowInsertStatementProvider<ProjectExperience> provider = insertMultiple(projects)
            .into(ProjectExperienceDynamicSqlSupport.projectExperience)
            .map(ProjectExperienceDynamicSqlSupport.employeeId).toProperty("employeeId")
            .map(ProjectExperienceDynamicSqlSupport.title).toProperty("title")
            .map(ProjectExperienceDynamicSqlSupport.content).toProperty("content")
            .map(ProjectExperienceDynamicSqlSupport.role).toProperty("role")
            .map(ProjectExperienceDynamicSqlSupport.begin).toProperty("begin")
            .map(ProjectExperienceDynamicSqlSupport.end).toProperty("end")
            .build().render(RenderingStrategies.MYBATIS3);
        return commonCustomMapper.insertMultiple(provider);
    }

    private <T extends AbstractWhereDSL<?>> T applyQueryArgs(T where, EmployeeQueryRequestDTO dto) {
        where.and(EmployeeDynamicSqlSupport.userId, isEqualToWhenPresent(dto.getUserId()))
            .and(EmployeeDynamicSqlSupport.name, isLikeWhenPresent(dto.getName()).then(s -> "%"+s+"%"));
        if (null != dto.getStatus()) {
            where.and(EmployeeDynamicSqlSupport.status, isEqualTo(dto.getStatus().getValue()));
        }
        return where;
    }

}
